/*
 * This file is part of the openHiTLS project.
 *
 * openHiTLS is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <strings.h>
#include <ctype.h>
#include <pthread.h>
#ifdef __linux__
#include <sys/utsname.h>
#endif

#include "bsl_uio.h"
#include "bsl_print.h"
#include "bsl_errno.h"
#include "app_errno.h"
#include "app_help.h"
#include "app_opt.h"
#include "app_utils.h"
#include "app_print.h"
#include "app_list.h" /* HITLS_APP_GetCidByName / GetNameByCid */

#include "crypt_errno.h"
#include "crypt_algid.h"
#include "crypt_eal_md.h" /* CRYPT_EAL_MdNewCtx/Init/Update/Final ... */
#include "crypt_eal_cipher.h" /* CRYPT_EAL_CipherNewCtx/Init/Update/Final ... */
#include "crypt_eal_rand.h"
#include "crypt_bn.h"
#include "crypt_eal_pkey.h"

#include <float.h>
#ifndef BENCH_SECS_EPS
#define BENCH_SECS_EPS 1e-9 /* 1 ns 级别：与 NsNow() 的纳秒刻度一致，更稳妥 */
#endif

#define BENCH_DEFAULT_SECONDS   3
#define BENCH_DEFAULT_SIZES_CNT 6
static const uint32_t g_defaultSizes[BENCH_DEFAULT_SIZES_CNT] = {16, 64, 256, 1024, 8192, 16384};
#define BENCH_MAX_EVP_NAME 64
#define BENCH_MAX_SIZES    16

#define BENCH_DEFAULT_PRIMES_CNT 4
static const uint32_t g_defaultPrimeSizes[BENCH_DEFAULT_PRIMES_CNT] = {1024, 2048, 3072, 4096};
#define BENCH_MAX_PRIME_SIZES 8

#define BENCH_MAX_PATH 256
#define BENCH_MAX_QUERY 128
typedef enum {
    HITLS_APP_OPT_EVP = 2,
    HITLS_APP_OPT_SECONDS,
    HITLS_APP_OPT_BYTES,
    HITLS_APP_OPT_DECRYPT,
    HITLS_APP_OPT_ELAPSED,
    HITLS_APP_OPT_MR,
    HITLS_APP_OPT_MULTI,
    HITLS_APP_OPT_PRIMES,
    HITLS_APP_OPT_VERBOSE,
    HITLS_APP_OPT_MLOCK,
    HITLS_APP_OPT_AEAD,
    HITLS_APP_OPT_HMAC,
    HITLS_APP_OPT_CMAC,
    HITLS_APP_OPT_MISALIGN,
    HITLS_APP_OPT_PROVIDER_PATH,
    HITLS_APP_OPT_PROPQUERY,
    HITLS_APP_OPT_ASYNC_JOBS,   // ✅ 新增
} BenchOptType;

typedef enum {
    BENCH_ALG_UNKNOWN = 0,
    BENCH_ALG_MD,
    BENCH_ALG_CIPHER,
    BENCH_ALG_RSA,
    BENCH_ALG_PRIME,
    BENCH_ALG_HMAC,
    BENCH_ALG_CMAC,
} BenchAlgKind;

typedef struct {
    char evpName[BENCH_MAX_EVP_NAME]; /* 兼容 OpenSSL -evp 语义 */
    BenchAlgKind kind;
    uint32_t mdId; /* CRYPT_MD_AlgId */
    uint32_t ciphId; /* CRYPT_CIPHER_AlgId */

    /* Provider 相关配置 */
    char providerPath[BENCH_MAX_PATH]; /* provider 路径 */
    char propQuery[BENCH_MAX_QUERY]; 

    /* 时间/尺寸控制 */
    uint32_t seconds;
    bool useBytesOnly;
    uint32_t bytes; /* -bytes 指定单一尺寸 */
    uint32_t sizes[BENCH_MAX_SIZES];
    uint32_t sizesCnt;

    /* 开关 */
    bool decrypt; /* 对称算法 -decrypt */
    bool elapsed; /* 计时输出切换 */
    bool mr; /* 机器可读 */
    uint32_t multi; /* TODO: -multi */
    bool mlock;
    bool primes;
    uint32_t primeSizes[BENCH_MAX_PRIME_SIZES];
    uint32_t primeSizesCnt;
    bool verbose;
    bool aead; /* 是否为 AEAD 算法 */
    uint32_t misalign;
    uint32_t asyncJobs;   /* 异步作业数量，0 表示未启用 */
    /* 输出 */
    BSL_UIO *outUio;
} BenchOptCtx;

/* 选项表 */
const HITLS_CmdOption g_benchOpts[] = {
    {"help", HITLS_APP_OPT_HELP, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "Display this function summary"},
    {"evp", HITLS_APP_OPT_EVP, HITLS_APP_OPT_VALUETYPE_STRING, "Algorithm name (digest or cipher)"},
    {"seconds", HITLS_APP_OPT_SECONDS, HITLS_APP_OPT_VALUETYPE_POSITIVE_INT, "Duration per size in seconds (def 3)"},
    {"bytes", HITLS_APP_OPT_BYTES, HITLS_APP_OPT_VALUETYPE_POSITIVE_INT, "Single buffer size; overrides defaults"},
    {"decrypt", HITLS_APP_OPT_DECRYPT, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "For ciphers: measure decrypt"},
    {"elapsed", HITLS_APP_OPT_ELAPSED, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "Use elapsed (wall-clock)"},
    {"mr", HITLS_APP_OPT_MR, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "Machine-readable output"},
    {"multi", HITLS_APP_OPT_MULTI, HITLS_APP_OPT_VALUETYPE_POSITIVE_INT, "Run N worker threads"},
    {"primes", HITLS_APP_OPT_PRIMES, HITLS_APP_OPT_VALUETYPE_POSITIVE_INT,
     "Test prime number generation for a specific bit size"},
    {"verbose", HITLS_APP_OPT_VERBOSE, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "Verbose output with detailed information"},
    {"mlock", HITLS_APP_OPT_MLOCK, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "Lock memory to prevent swapping"},
    {"aead", HITLS_APP_OPT_AEAD, HITLS_APP_OPT_VALUETYPE_NO_VALUE, "For AEAD: run full AEAD sequence (aad/final/tag)"},
    {"hmac", HITLS_APP_OPT_HMAC, HITLS_APP_OPT_VALUETYPE_STRING, "HMAC with <digest> (e.g. sha256)"},
    {"cmac", HITLS_APP_OPT_CMAC, HITLS_APP_OPT_VALUETYPE_STRING, "CMAC with <cipher> (e.g. aes128|aes-128-cbc)"},
    {"misalign", HITLS_APP_OPT_MISALIGN, HITLS_APP_OPT_VALUETYPE_POSITIVE_INT, "Misalign input buffer by N bytes"},
    {"provider-path", HITLS_APP_OPT_PROVIDER_PATH, HITLS_APP_OPT_VALUETYPE_STRING, "Provider path to load"},
    {"propquery", HITLS_APP_OPT_PROPQUERY, HITLS_APP_OPT_VALUETYPE_STRING, "Property query string for provider"},
    {"async_jobs", HITLS_APP_OPT_ASYNC_JOBS, HITLS_APP_OPT_VALUETYPE_POSITIVE_INT, "Enable async mode with N jobs"},
    {NULL},
};

/* --------- 工具：计时 --------- */
/* 全局：是否使用 elapsed（墙钟时间）；默认使用 CPU 时间以对齐 OpenSSL 的语义 */
static bool g_bench_use_elapsed = false;

static int32_t BenchOptAead(BenchOptCtx *optCtx)
{
    optCtx->aead = true;
    return HITLS_APP_SUCCESS;
}

static inline uint64_t NsNow(void)
{
    struct timespec ts;
    if (g_bench_use_elapsed) {
        /* 墙钟时间（单调时钟），对应 openssl speed 的 -elapsed */
        clock_gettime(CLOCK_MONOTONIC, &ts);
    } else {
        /* 进程 CPU 时间（user+sys），对应 openssl speed 的默认语义 */
        clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
    }
    return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec;
}

/* --------- 系统信息获取 --------- */
static void PrintSystemInfo(BenchOptCtx *opt)
{
    if (!opt->verbose) {
        return;
    }

    BSL_PRINT_Fmt(0, opt->outUio, "openHiTLS Benchmark Tool\n");
    BSL_PRINT_Fmt(0, opt->outUio, "========================================\n");
    if (opt->misalign > 0) {
        BSL_PRINT_Fmt(0, opt->outUio, "Buffer misalignment: %u bytes\n", opt->misalign);
    }
#ifdef __linux__
    /* 系统信息 */
    struct utsname sysinfo;
    if (uname(&sysinfo) == 0) {
        BSL_PRINT_Fmt(0, opt->outUio, "System: %s %s %s\n", sysinfo.sysname, sysinfo.release, sysinfo.machine);
    }
#endif

    /* CPU信息 */
    FILE *cpuinfo = fopen("/proc/cpuinfo", "r");
    if (cpuinfo) {
        char line[256];
        bool found_model = false;
        while (fgets(line, sizeof(line), cpuinfo) && !found_model) {
            if (strncmp(line, "model name", 10) == 0) {
                char *colon = strchr(line, ':');
                if (colon) {
                    char *model = colon + 2;
                    char *newline = strchr(model, '\n');
                    if (newline) {
                        *newline = '\0';
                    }
                    BSL_PRINT_Fmt(0, opt->outUio, "CPU: %s\n", model);
                    found_model = true;
                }
            }
        }
        fclose(cpuinfo);
        if (!found_model) {
            BSL_PRINT_Fmt(0, opt->outUio, "CPU: Information not available\n");
        }
    }

    /* 运行配置 */
    BSL_PRINT_Fmt(0, opt->outUio, "Test duration: %u seconds per test\n", opt->seconds);
    BSL_PRINT_Fmt(0, opt->outUio, "Timer precision: nanosecond (CLOCK_MONOTONIC)\n");
    if (opt->multi > 1) {
        BSL_PRINT_Fmt(0, opt->outUio, "Multi-threading: %u threads\n", opt->multi);
    }
    BSL_PRINT_Fmt(0, opt->outUio, "========================================\n\n");
}

static void PrintProgress(BenchOptCtx *opt, const char *stage, uint32_t current, uint32_t total)
{
    if (!opt->verbose) {
        return;
    }
    BSL_PRINT_Fmt(0, opt->outUio, "[%u/%u] %s... ", current + 1, total, stage);
    fflush(stdout);
}

static void PrintProgressDone(BenchOptCtx *opt)
{
    if (!opt->verbose) {
        return;
    }
    BSL_PRINT_Fmt(0, opt->outUio, "Done.\n");
}
/* --------- 选项解析 --------- */
static void InitBenchOptCtx(BenchOptCtx *ctx)
{
    memset(ctx, 0, sizeof(*ctx));
    ctx->seconds = BENCH_DEFAULT_SECONDS;
    memcpy(ctx->sizes, g_defaultSizes, sizeof(g_defaultSizes));
    ctx->sizesCnt = BENCH_DEFAULT_SIZES_CNT;
    memcpy(ctx->primeSizes, g_defaultPrimeSizes, sizeof(g_defaultPrimeSizes));
    ctx->primeSizesCnt = BENCH_DEFAULT_PRIMES_CNT;
    ctx->kind = BENCH_ALG_UNKNOWN;
    ctx->misalign = 0;
    ctx->providerPath[0] = '\0';
    ctx->propQuery[0] = '\0';
}

static int32_t BenchOptProviderPath(BenchOptCtx *optCtx)
{
   char *path = HITLS_APP_OptGetValueStr();
    if (path == NULL || strlen(path) >= BENCH_MAX_PATH) {
        AppPrintError("bench: invalid -provider-path.\n");
        return HITLS_APP_OPT_VALUE_INVALID;
    }
    (void)strncpy(optCtx->providerPath, path, BENCH_MAX_PATH - 1);
    return HITLS_APP_SUCCESS;
}

static int32_t BenchOptPropquery(BenchOptCtx *optCtx)
{
    char *query = HITLS_APP_OptGetValueStr();
    if (query == NULL || strlen(query) >= BENCH_MAX_QUERY) {
        AppPrintError("bench: invalid -propquery.\n");
            return HITLS_APP_OPT_VALUE_INVALID;
    }
    (void)strncpy(optCtx->propQuery, query, BENCH_MAX_QUERY - 1);
    return HITLS_APP_SUCCESS;
}

static int32_t BenchOptErr(BenchOptCtx *optCtx)
{
    (void)optCtx;
    AppPrintError("bench: Use -help for summary.\n");
    return HITLS_APP_OPT_UNKOWN;
}

static int32_t BenchOptHelp(BenchOptCtx *optCtx)
{
    (void)optCtx;
    HITLS_APP_OptHelpPrint(g_benchOpts);
    return HITLS_APP_HELP;
}

/* app_bench.c: 替换 BenchOptEvp，仅此一处 */
static int32_t BenchOptEvp(BenchOptCtx *optCtx)
{
    const char *nameIn = HITLS_APP_OptGetValueStr();
    if (nameIn == NULL || strlen(nameIn) >= BENCH_MAX_EVP_NAME) {
        AppPrintError("bench: invalid -evp.\n");
        return HITLS_APP_OPT_VALUE_INVALID;
    }
    /* 保存用户原始输入（用于打印） */
    (void)strncpy(optCtx->evpName, nameIn, BENCH_MAX_EVP_NAME - 1);

    /* 1) 先按 openssl 风格名称做“本地映射”（不产生任何 Unsupport 噪音） */
    typedef struct {
        const char *name; /* -evp 名称（小写，连字符） */
        BenchAlgKind kind;
        uint32_t algId; /* CRYPT_MD_AlgId 或 CRYPT_CIPHER_AlgId */
    } AlgMap;

    static const AlgMap kMap[] = {
        /* digests */
        {"md5", BENCH_ALG_MD, CRYPT_MD_MD5},
        {"sha1", BENCH_ALG_MD, CRYPT_MD_SHA1},
        {"sha224", BENCH_ALG_MD, CRYPT_MD_SHA224},
        {"sha256", BENCH_ALG_MD, CRYPT_MD_SHA256},
        {"sha384", BENCH_ALG_MD, CRYPT_MD_SHA384},
        {"sha512", BENCH_ALG_MD, CRYPT_MD_SHA512},
        {"sha3-224", BENCH_ALG_MD, CRYPT_MD_SHA3_224},
        {"sha3-256", BENCH_ALG_MD, CRYPT_MD_SHA3_256},
        {"sha3-384", BENCH_ALG_MD, CRYPT_MD_SHA3_384},
        {"sha3-512", BENCH_ALG_MD, CRYPT_MD_SHA3_512},
        {"shake128", BENCH_ALG_MD, CRYPT_MD_SHAKE128},
        {"shake256", BENCH_ALG_MD, CRYPT_MD_SHAKE256},
        {"sm3", BENCH_ALG_MD, CRYPT_MD_SM3},

        /* ciphers（openssl 的 -evp 名 → openHiTLS 的 CRYPT_CIPHER_AlgId） */
        {"aes-128-cbc", BENCH_ALG_CIPHER, CRYPT_CIPHER_AES128_CBC},
        {"aes-192-cbc", BENCH_ALG_CIPHER, CRYPT_CIPHER_AES192_CBC},
        {"aes-256-cbc", BENCH_ALG_CIPHER, CRYPT_CIPHER_AES256_CBC},
        {"aes-128-ctr", BENCH_ALG_CIPHER, CRYPT_CIPHER_AES128_CTR},
        {"aes-192-ctr", BENCH_ALG_CIPHER, CRYPT_CIPHER_AES192_CTR},
        {"aes-256-ctr", BENCH_ALG_CIPHER, CRYPT_CIPHER_AES256_CTR},
        {"aes-128-gcm", BENCH_ALG_CIPHER, CRYPT_CIPHER_AES128_GCM},
        {"aes-192-gcm", BENCH_ALG_CIPHER, CRYPT_CIPHER_AES192_GCM},
        {"aes-256-gcm", BENCH_ALG_CIPHER, CRYPT_CIPHER_AES256_GCM},
        {"chacha20-poly1305", BENCH_ALG_CIPHER, CRYPT_CIPHER_CHACHA20_POLY1305},
        {"sm4-cbc", BENCH_ALG_CIPHER, CRYPT_CIPHER_SM4_CBC},
        {"sm4-ctr", BENCH_ALG_CIPHER, CRYPT_CIPHER_SM4_CTR},
        {"sm4-gcm", BENCH_ALG_CIPHER, CRYPT_CIPHER_SM4_GCM},
        {"sm4-cfb", BENCH_ALG_CIPHER, CRYPT_CIPHER_SM4_CFB},
        {"sm4-ofb", BENCH_ALG_CIPHER, CRYPT_CIPHER_SM4_OFB},
        {"sm4-xts", BENCH_ALG_CIPHER, CRYPT_CIPHER_SM4_XTS},
    };

    /* 做不区分大小写匹配（把输入转小写再比对或用 strcasecmp） */
    for (size_t i = 0; i < sizeof(kMap) / sizeof(kMap[0]); ++i) {
        if (strcasecmp(nameIn, kMap[i].name) == 0) {
            optCtx->kind = kMap[i].kind;
            if (optCtx->kind == BENCH_ALG_MD) {
                optCtx->mdId = kMap[i].algId;
            } else {
                optCtx->ciphId = kMap[i].algId;
            }
            return HITLS_APP_SUCCESS;
        }
    }

    /* 2) 本地映射没命中时，再调用 openHiTLS 的名字解析（只尝试“看上去像 MD”或“像 CIPHER”的那一类，避免多次失败打印） */
    bool looksMd = (strncasecmp(nameIn, "sha", 3) == 0) || (strncasecmp(nameIn, "sm3", 3) == 0) ||
                   (strcasecmp(nameIn, "md5") == 0);

    if (looksMd) {
        uint32_t mdId = HITLS_APP_GetCidByName(nameIn, HITLS_APP_LIST_OPT_DGST_ALG);
        if (mdId != BSL_CID_UNKNOWN) {
            optCtx->kind = BENCH_ALG_MD;
            optCtx->mdId = mdId;
            return HITLS_APP_SUCCESS;
        }
    } else {
        uint32_t ciphId = HITLS_APP_GetCidByName(nameIn, HITLS_APP_LIST_OPT_CIPHER_ALG);
        if (ciphId != BSL_CID_UNKNOWN) {
            optCtx->kind = BENCH_ALG_CIPHER;
            optCtx->ciphId = ciphId;
            return HITLS_APP_SUCCESS;
        }
    }

    AppPrintError("bench: unsupported -evp %s.\n", nameIn);
    return HITLS_APP_OPT_VALUE_INVALID;
}

static int32_t BenchOptSeconds(BenchOptCtx *optCtx)
{
    return HITLS_APP_OptGetUint32(HITLS_APP_OptGetValueStr(), &optCtx->seconds);
}

static int32_t BenchOptBytes(BenchOptCtx *optCtx)
{
    int32_t ret = HITLS_APP_OptGetUint32(HITLS_APP_OptGetValueStr(), &optCtx->bytes);
    if (ret == HITLS_APP_SUCCESS) {
        optCtx->useBytesOnly = true;
        optCtx->sizes[0] = optCtx->bytes;
        optCtx->sizesCnt = 1;
    }
    return ret;
}

static int32_t BenchOptHmac(BenchOptCtx *optCtx)
{
    const char *v = HITLS_APP_OptGetValueStr();
    if (v == NULL || strlen(v) >= BENCH_MAX_EVP_NAME) {
        return HITLS_APP_OPT_VALUE_INVALID;
    }
    strncpy(optCtx->evpName, v, BENCH_MAX_EVP_NAME - 1);
    optCtx->kind = BENCH_ALG_HMAC;
    uint32_t id = HITLS_APP_GetCidByName(v, HITLS_APP_LIST_OPT_DGST_ALG); // 仅用于友好显示
    if (id != BSL_CID_UNKNOWN) {
        optCtx->mdId = id;
    }
    return HITLS_APP_SUCCESS;
}

static int32_t BenchOptCmac(BenchOptCtx *optCtx)
{
    const char *v = HITLS_APP_OptGetValueStr();
    if (v == NULL || strlen(v) >= BENCH_MAX_EVP_NAME) {
        return HITLS_APP_OPT_VALUE_INVALID;
    }
    const char *name = (!strcasecmp(v, "aes128") ? "aes-128-cbc" : v); // 兼容别名
    strncpy(optCtx->evpName, name, BENCH_MAX_EVP_NAME - 1);
    optCtx->kind = BENCH_ALG_CMAC;
    uint32_t id = HITLS_APP_GetCidByName(name, HITLS_APP_LIST_OPT_CIPHER_ALG);
    if (id != BSL_CID_UNKNOWN) {
        optCtx->ciphId = id;
    }
    return HITLS_APP_SUCCESS;
}

static int32_t BenchOptDecrypt(BenchOptCtx *optCtx)
{
    optCtx->decrypt = true;
    return HITLS_APP_SUCCESS;
}
static int32_t BenchOptElapsed(BenchOptCtx *optCtx)
{
    optCtx->elapsed = true;
    g_bench_use_elapsed = true;
    return HITLS_APP_SUCCESS;
}
static int32_t BenchOptMr(BenchOptCtx *optCtx)
{
    optCtx->mr = true;
    return HITLS_APP_SUCCESS;
}
static int32_t BenchOptMulti(BenchOptCtx *optCtx)
{
    return HITLS_APP_OptGetUint32(HITLS_APP_OptGetValueStr(), &optCtx->multi);
}
static int32_t BenchOptMlock(BenchOptCtx *optCtx)
{
    optCtx->mlock = true; // 标记需要启用内存锁定
    return HITLS_APP_SUCCESS;
}
static int32_t BenchOptPrimes(BenchOptCtx *optCtx)
{
    optCtx->primes = true;
    optCtx->kind = BENCH_ALG_PRIME;

    uint32_t primeBits;
    // 从命令行获取 -primes 选项的整数值
    int32_t ret = HITLS_APP_OptGetUint32(HITLS_APP_OptGetValueStr(), &primeBits);
    if (ret != HITLS_APP_SUCCESS) {
        AppPrintError("bench: invalid value for -primes.\n");
        return ret;
    }
    optCtx->primeSizes[0] = primeBits;
    optCtx->primeSizesCnt = 1;
    return HITLS_APP_SUCCESS;
}

static int32_t BenchOptVerbose(BenchOptCtx *optCtx)
{
    optCtx->verbose = true;
    return HITLS_APP_SUCCESS;
}
typedef int32_t (*BenchOptHandle)(BenchOptCtx *);
typedef struct {
    int optType;
    BenchOptHandle fn;
} BenchOptHandleMap;

static int32_t BenchOptMisalign(BenchOptCtx *optCtx)
{
    return HITLS_APP_OptGetUint32(HITLS_APP_OptGetValueStr(), &optCtx->misalign);
}

static int32_t BenchOptAsyncJobs(BenchOptCtx *optCtx)
{
    return HITLS_APP_OptGetUint32(HITLS_APP_OptGetValueStr(), &optCtx->asyncJobs);
}


static const BenchOptHandleMap g_benchOptHandles[] = {
    {HITLS_APP_OPT_ERR, BenchOptErr},          {HITLS_APP_OPT_HELP, BenchOptHelp},
    {HITLS_APP_OPT_EVP, BenchOptEvp},          {HITLS_APP_OPT_SECONDS, BenchOptSeconds},
    {HITLS_APP_OPT_BYTES, BenchOptBytes},      {HITLS_APP_OPT_DECRYPT, BenchOptDecrypt},
    {HITLS_APP_OPT_ELAPSED, BenchOptElapsed},  {HITLS_APP_OPT_MR, BenchOptMr},
    {HITLS_APP_OPT_MULTI, BenchOptMulti},      {HITLS_APP_OPT_PRIMES, BenchOptPrimes},
    {HITLS_APP_OPT_VERBOSE, BenchOptVerbose},  {HITLS_APP_OPT_MULTI, BenchOptMulti},
    {HITLS_APP_OPT_MLOCK, BenchOptMlock},      {HITLS_APP_OPT_AEAD, BenchOptAead},
    {HITLS_APP_OPT_HMAC, BenchOptHmac},        {HITLS_APP_OPT_CMAC, BenchOptCmac},
    {HITLS_APP_OPT_MISALIGN, BenchOptMisalign}, {HITLS_APP_OPT_PROVIDER_PATH, BenchOptProviderPath},
    {HITLS_APP_OPT_PROPQUERY, BenchOptPropquery}, {HITLS_APP_OPT_ASYNC_JOBS, BenchOptAsyncJobs},
};

static int32_t ParseBenchOpt(int argc, char *argv[], BenchOptCtx *optCtx)
{
    int32_t ret = HITLS_APP_OptBegin(argc, argv, g_benchOpts);
    if (ret != HITLS_APP_SUCCESS) {
        HITLS_APP_OptEnd();
        AppPrintError("bench: opt begin failed.\n");
        return ret;
    }
    int optType = HITLS_APP_OPT_ERR;
    while ((ret == HITLS_APP_SUCCESS) && ((optType = HITLS_APP_OptNext()) != HITLS_APP_OPT_EOF)) {
        size_t i;
        for (i = 0; i < sizeof(g_benchOptHandles) / sizeof(g_benchOptHandles[0]); ++i) {
            if (optType == g_benchOptHandles[i].optType) {
                ret = g_benchOptHandles[i].fn(optCtx);
                break;
            }
        }
        if (i == sizeof(g_benchOptHandles) / sizeof(g_benchOptHandles[0])) {
            AppPrintError("bench: unhandled option type %d.\n", optType);
            ret = HITLS_APP_OPT_UNKOWN;
        }
    }
    if ((ret == HITLS_APP_SUCCESS) && (HITLS_APP_GetRestOptNum() != 0)) {
        AppPrintError("bench: Extra arguments. Use -help.\n");
        ret = HITLS_APP_OPT_UNKOWN;
    }
    HITLS_APP_OptEnd();
    /* 验证选项组合 */
    if (ret == HITLS_APP_SUCCESS && optCtx->kind == BENCH_ALG_UNKNOWN) {
        AppPrintError("bench: please specify -evp <alg>.\n");
        ret = HITLS_APP_OPT_VALUE_INVALID;
    }
    /* verbose 和 mr 互斥检查 */
    if (ret == HITLS_APP_SUCCESS && optCtx->verbose && optCtx->mr) {
        AppPrintError("bench: -verbose and -mr options are mutually exclusive.\n");
        ret = HITLS_APP_OPT_VALUE_INVALID;
    }
    return ret;
}

/* --------- 测试内核：MD --------- */
static int32_t RunMdOnce(uint32_t mdId, uint32_t sz, uint32_t seconds, double *bytesPerSecOut, uint32_t misalign)
{
    int32_t ret = HITLS_APP_SUCCESS;
    CRYPT_EAL_MdCTX *ctx = CRYPT_EAL_MdNewCtx((CRYPT_MD_AlgId)mdId);
    if (ctx == NULL) {
        return HITLS_APP_MEM_ALLOC_FAIL;
    }

    uint8_t *base = (uint8_t *)malloc(sz + misalign);
    if (base == NULL) {
        CRYPT_EAL_MdFreeCtx(ctx);
        return HITLS_APP_MEM_ALLOC_FAIL;
    }
    uint8_t *buf = base + misalign;
    memset(base, 0xA5, sz + misalign);

    if (CRYPT_EAL_MdInit(ctx) != CRYPT_SUCCESS) {
        ret = HITLS_APP_CRYPTO_FAIL;
        goto EXIT;
    }

    uint64_t start = NsNow();
    uint64_t endNs = start + (uint64_t)seconds * 1000000000ull;
    uint64_t processed = 0;
    uint64_t loops = 0;
    uint8_t out[128]; /* 足够容纳常见摘要 */
    uint32_t outLen = sizeof(out);

    while (NsNow() < endNs) {
        if (CRYPT_EAL_MdUpdate(ctx, buf, sz) != CRYPT_SUCCESS) {
            ret = HITLS_APP_CRYPTO_FAIL;
            break;
        }
        processed += sz;
        loops++;
        /* 可选择性地周期 Final+Reinit 防止内部状态过大（多数 MD 不需要） */
        if ((processed / sz) % 1024 == 0) {
            outLen = sizeof(out);
            if (CRYPT_EAL_MdFinal(ctx, out, &outLen) != CRYPT_SUCCESS) {
                ret = HITLS_APP_CRYPTO_FAIL;
                break;
            }
            if (CRYPT_EAL_MdInit(ctx) != CRYPT_SUCCESS) {
                ret = HITLS_APP_CRYPTO_FAIL;
                break;
            }
        }
    }
    /* 最后一笔 Final（避免被编译器消除） */
    outLen = sizeof(out);
    if (CRYPT_EAL_MdFinal(ctx, out, &outLen) != CRYPT_SUCCESS) {
        ret = HITLS_APP_CRYPTO_FAIL;
    }
    double secs = (double)(NsNow() - start) / 1e9;
    /* 避免极端情况下分母过小；同时规避 -Werror=float-equal */
    if (secs <= BENCH_SECS_EPS) {
        secs = BENCH_SECS_EPS;
    }
    *bytesPerSecOut = (double)processed / secs;

EXIT:
    free(buf);
    free(base);
    CRYPT_EAL_MdFreeCtx(ctx);
    return ret;
}


static int32_t InitCryptoProvider(BenchOptCtx *opt)
{

    if (opt->providerPath[0] != '\0' || opt->propQuery[0] != '\0') {

        if (!opt->mr) {
            if (opt->providerPath[0] != '\0') {
                BSL_PRINT_Fmt(0, opt->outUio, "Using provider from: %s\n", opt->providerPath);
            }
            if (opt->propQuery[0] != '\0') {
                BSL_PRINT_Fmt(0, opt->outUio, "Using property query: %s\n", opt->propQuery);
            }
        }
    }
    return HITLS_APP_SUCCESS;
}

static uint32_t MdBlockSizeById(uint32_t mdId)
{
    switch ((CRYPT_MD_AlgId)mdId) {
        case CRYPT_MD_MD5:
        case CRYPT_MD_SHA1:
        case CRYPT_MD_SHA224:
        case CRYPT_MD_SHA256:
        case CRYPT_MD_SM3:
            return 64;
        case CRYPT_MD_SHA384:
        case CRYPT_MD_SHA512:
            return 128;
        default:
            return 0; /* 未支持的作为错误处理 */
    }
}

static int32_t RunHmacOnce(const char *dgstName, uint32_t sz, uint32_t seconds, double *bytesPerSecOut)
{
    /* 解析 mdId（允许用户给 sha-256/sha256 等） */
    uint32_t mdId = HITLS_APP_GetCidByName(dgstName, HITLS_APP_LIST_OPT_DGST_ALG);
    if (mdId == BSL_CID_UNKNOWN) {
        return HITLS_APP_OPT_VALUE_INVALID;
    }

    uint32_t bsz = MdBlockSizeById(mdId);
    if (bsz == 0) {
        return HITLS_APP_OPT_VALUE_INVALID;
    }

    CRYPT_EAL_MdCTX *md = CRYPT_EAL_MdNewCtx((CRYPT_MD_AlgId)mdId);
    if (!md) {
        return HITLS_APP_MEM_ALLOC_FAIL;
    }

    uint8_t *msg = (uint8_t *)malloc(sz);
    if (!msg) {
        CRYPT_EAL_MdFreeCtx(md);
        return HITLS_APP_MEM_ALLOC_FAIL;
    }
    memset(msg, 0x36, sz);

    uint8_t key[32];
    memset(key, 0xA5, sizeof(key));
    /* 预构造 ipad/opad */
    uint8_t ipad[128] = {0}, opad[128] = {0};
    for (uint32_t i = 0; i < bsz; ++i) {
        uint8_t k = (i < sizeof(key)) ? key[i] : 0x00;
        ipad[i] = (uint8_t)(k ^ 0x36);
        opad[i] = (uint8_t)(k ^ 0x5c);
    }

    uint8_t inner[128];
    uint32_t innerLen = sizeof(inner);
    uint8_t tag[128];
    uint32_t tagLen = sizeof(tag);

    uint64_t start = NsNow(), endNs = start + (uint64_t)seconds * 1000000000ull;
    uint64_t processed = 0;

    while (NsNow() < endNs) {
        /* inner = H( (K^ipad) || msg ) */
        if (CRYPT_EAL_MdInit(md) != CRYPT_SUCCESS) {
            processed = 0;
            break;
        }
        if (CRYPT_EAL_MdUpdate(md, ipad, bsz) != CRYPT_SUCCESS) {
            processed = 0;
            break;
        }
        if (CRYPT_EAL_MdUpdate(md, msg, sz) != CRYPT_SUCCESS) {
            processed = 0;
            break;
        }
        innerLen = sizeof(inner);
        if (CRYPT_EAL_MdFinal(md, inner, &innerLen) != CRYPT_SUCCESS) {
            processed = 0;
            break;
        }

        /* tag = H( (K^opad) || inner ) */
        if (CRYPT_EAL_MdInit(md) != CRYPT_SUCCESS) {
            processed = 0;
            break;
        }
        if (CRYPT_EAL_MdUpdate(md, opad, bsz) != CRYPT_SUCCESS) {
            processed = 0;
            break;
        }
        if (CRYPT_EAL_MdUpdate(md, inner, innerLen) != CRYPT_SUCCESS) {
            processed = 0;
            break;
        }
        tagLen = sizeof(tag);
        if (CRYPT_EAL_MdFinal(md, tag, &tagLen) != CRYPT_SUCCESS) {
            processed = 0;
            break;
        }

        processed += sz;
    }

    double secs = (double)(NsNow() - start) / 1e9;
    if (secs <= BENCH_SECS_EPS) {
        secs = BENCH_SECS_EPS;
    }
    *bytesPerSecOut = (double)processed / secs;

    free(msg);
    CRYPT_EAL_MdFreeCtx(md);
    return processed ? HITLS_APP_SUCCESS : HITLS_APP_CRYPTO_FAIL;
}

#if 0
/* GF(2^n) 左移一位（大端），若溢出则异或 Rb（128 位用 0x87，64 位用 0x1B） */
static void GF_Double_BE(uint8_t* blk, uint32_t n, uint8_t Rb)
{
    uint8_t carry = 0;
    for (int i = (int)n - 1; i >= 0; --i) {
        uint8_t x = blk[i];
        uint8_t c = (uint8_t)((x & 0x80) ? 1 : 0);
        blk[i] = (uint8_t)((x << 1) | carry);
        carry = c;
    }
    if (carry) blk[n - 1] ^= Rb;
}
#endif
/* 取 CMAC 所需的 keyLen / blockSize（= CBC 的 IV 长） */
static void CmacKeyBlkLenByCipher(uint32_t ciphId, uint32_t *keyLen, uint32_t *blk)
{
    switch ((CRYPT_CIPHER_AlgId)ciphId) {
        case CRYPT_CIPHER_AES128_CBC:
            *keyLen = 16;
            *blk = 16;
            return;
        case CRYPT_CIPHER_AES192_CBC:
            *keyLen = 24;
            *blk = 16;
            return;
        case CRYPT_CIPHER_AES256_CBC:
            *keyLen = 32;
            *blk = 16;
            return;
        case CRYPT_CIPHER_SM4_CBC:
            *keyLen = 16;
            *blk = 16;
            return;
        default:
            *keyLen = 0;
            *blk = 0;
            return;
    }
}

/* ---------- REPLACE the whole RunCmacOnce with this version ---------- */
static int32_t RunCmacOnce(const char *cipherNameIn, uint32_t sz, uint32_t seconds, double *bytesPerSecOut)
{
    const char *name = (!strcasecmp(cipherNameIn, "aes128") ? "aes-128-cbc" : cipherNameIn);
    uint32_t ciphId = HITLS_APP_GetCidByName(name, HITLS_APP_LIST_OPT_CIPHER_ALG);
    if (ciphId == BSL_CID_UNKNOWN) {
        AppPrintError("Unsupport cipher: %s\n", name);
        return HITLS_APP_OPT_VALUE_INVALID;
    }

    uint32_t keyLen = 0, blk = 0;
    CmacKeyBlkLenByCipher(ciphId, &keyLen, &blk);
    if (keyLen == 0 || blk == 0) {
        AppPrintError("Unsupport cipher: %s\n", name);
        return HITLS_APP_OPT_VALUE_INVALID;
    }
    if (sz == 0 || (sz % blk) != 0) {
        AppPrintError("cmac size %u must be multiple of block %u\n", sz, blk);
        return HITLS_APP_OPT_VALUE_INVALID;
    }

    CRYPT_EAL_CipherCtx *ctx = CRYPT_EAL_CipherNewCtx((CRYPT_CIPHER_AlgId)ciphId);
    if (!ctx) {
        return HITLS_APP_MEM_ALLOC_FAIL;
    }

    uint8_t *msg = (uint8_t *)malloc(sz);
    uint8_t *buf = (uint8_t *)malloc(sz);
    uint8_t *out = (uint8_t *)malloc(sz);
    if (!msg || !buf || !out) {
        CRYPT_EAL_CipherFreeCtx(ctx);
        free(msg);
        free(buf);
        free(out);
        return HITLS_APP_MEM_ALLOC_FAIL;
    }
    memset(msg, 0x5C, sz);

    uint8_t key[32];
    memset(key, 0xA5, keyLen);
    uint8_t iv[16];
    memset(iv, 0x00, sizeof(iv));
    (void)CRYPT_EAL_CipherSetPadding(ctx, CRYPT_PADDING_NONE);

    /* 预计算 L/K1/K2: L = E_K(0^n)，然后 gf(2^n) 左移 */
    uint8_t L[16] = {0}, K1[16], K2[16];
    uint8_t zero[16] = {0};
    {
        if (CRYPT_EAL_CipherInit(ctx, key, keyLen, iv, blk, /*enc=*/true) != CRYPT_SUCCESS) {
            CRYPT_EAL_CipherFreeCtx(ctx);
            free(msg);
            free(buf);
            free(out);
            return HITLS_APP_CRYPTO_FAIL;
        }
        uint32_t lout = blk;
        if (CRYPT_EAL_CipherUpdate(ctx, zero, blk, L, &lout) != CRYPT_SUCCESS || lout != blk) {
            CRYPT_EAL_CipherFreeCtx(ctx);
            free(msg);
            free(buf);
            free(out);
            return HITLS_APP_CRYPTO_FAIL;
        }
        memcpy(K1, L, blk);
        uint8_t Rb = (blk == 16 ? 0x87 : 0x1B);
        {
            uint8_t carry = 0;
            for (int i = (int)blk - 1; i >= 0; --i) {
                uint8_t x = K1[i], c = (x & 0x80) ? 1 : 0;
                K1[i] = (uint8_t)((x << 1) | carry);
                carry = c;
            }
            if (carry) {
                K1[blk - 1] ^= Rb;
            }
        }
        memcpy(K2, K1, blk);
        {
            uint8_t carry = 0;
            for (int i = (int)blk - 1; i >= 0; --i) {
                uint8_t x = K2[i], c = (x & 0x80) ? 1 : 0;
                K2[i] = (uint8_t)((x << 1) | carry);
                carry = c;
            }
            if (carry) {
                K2[blk - 1] ^= Rb;
            }
        }
    }

    uint64_t start = NsNow(), endNs = start + (uint64_t)seconds * 1000000000ull;
    uint64_t processed = 0;

    while (NsNow() < endNs) {
        memcpy(buf, msg, sz);
        for (uint32_t i = 0; i < blk; ++i) {
            buf[sz - blk + i] ^= K1[i]; /* 全整块：最后一块 ^K1 */
        }

        if (CRYPT_EAL_CipherInit(ctx, key, keyLen, iv, blk, /*enc=*/true) != CRYPT_SUCCESS) {
            processed = 0;
            break;
        }
        uint32_t outLen = sz;
        if (CRYPT_EAL_CipherUpdate(ctx, buf, sz, out, &outLen) != CRYPT_SUCCESS || outLen != sz) {
            processed = 0;
            break;
        }
        (void)CRYPT_EAL_CipherFinal(ctx, out, &outLen);

        processed += sz;
    }

    double secs = (double)(NsNow() - start) / 1e9;
    if (secs <= BENCH_SECS_EPS) {
        secs = BENCH_SECS_EPS;
    }
    *bytesPerSecOut = (double)processed / secs;

    CRYPT_EAL_CipherFreeCtx(ctx);
    free(msg);
    free(buf);
    free(out);
    return processed ? HITLS_APP_SUCCESS : HITLS_APP_CRYPTO_FAIL;
}

/* 是否为 AEAD 算法 */
static inline bool IsAeadCipher(uint32_t ciphId)
{
    switch ((CRYPT_CIPHER_AlgId)ciphId) {
        case CRYPT_CIPHER_AES128_GCM:
        case CRYPT_CIPHER_AES192_GCM:
        case CRYPT_CIPHER_AES256_GCM:
        case CRYPT_CIPHER_CHACHA20_POLY1305:
        case CRYPT_CIPHER_SM4_GCM:
            return true;
        default:
            return false;
    }
}

/* --------- 测试内核：对称加/解密（非 AEAD） --------- */
static int32_t RunCipherOnce(uint32_t ciphId, bool decrypt, uint32_t sz, uint32_t seconds, double *bytesPerSecOut,
                             uint32_t misalign)
{
    int32_t ret = HITLS_APP_SUCCESS;
    CRYPT_EAL_CipherCtx *ctx = CRYPT_EAL_CipherNewCtx((CRYPT_CIPHER_AlgId)ciphId);
    if (ctx == NULL) {
        return HITLS_APP_MEM_ALLOC_FAIL;
    }

    /* 获取算法信息以决定 key/iv 大小（示例：用 GetInfo；实际请按 API 定义完善） */
    /* 针对不同算法设定常见的 key/iv 长度与模式特性 */
    uint32_t keyLen = 16, ivLen = 0;
    bool isBlockMode = true; /* 需要考虑 padding 的块模式（CBC/XTS/ECB等） */
    bool needNoPadding = false; /* 我们用整块大小跑分，CBC/XTS 关闭 padding 以便稳定循环 */
    switch ((CRYPT_CIPHER_AlgId)ciphId) {
        /* AES-CBC/CFB/OFB/CTR */
        case CRYPT_CIPHER_AES128_CBC:
            keyLen = 16;
            ivLen = 16;
            needNoPadding = true;
            break;
        case CRYPT_CIPHER_AES192_CBC:
            keyLen = 24;
            ivLen = 16;
            needNoPadding = true;
            break;
        case CRYPT_CIPHER_AES256_CBC:
            keyLen = 32;
            ivLen = 16;
            needNoPadding = true;
            break;

        case CRYPT_CIPHER_AES128_CTR:
            keyLen = 16;
            ivLen = 16;
            isBlockMode = false;
            break;
        case CRYPT_CIPHER_AES192_CTR:
            keyLen = 24;
            ivLen = 16;
            isBlockMode = false;
            break;
        case CRYPT_CIPHER_AES256_CTR:
            keyLen = 32;
            ivLen = 16;
            isBlockMode = false;
            break;

        case CRYPT_CIPHER_AES128_CFB:
            keyLen = 16;
            ivLen = 16;
            isBlockMode = false;
            break;
        case CRYPT_CIPHER_AES192_CFB:
            keyLen = 24;
            ivLen = 16;
            isBlockMode = false;
            break;
        case CRYPT_CIPHER_AES256_CFB:
            keyLen = 32;
            ivLen = 16;
            isBlockMode = false;
            break;

        case CRYPT_CIPHER_AES128_OFB:
            keyLen = 16;
            ivLen = 16;
            isBlockMode = false;
            break;
        case CRYPT_CIPHER_AES192_OFB:
            keyLen = 24;
            ivLen = 16;
            isBlockMode = false;
            break;
        case CRYPT_CIPHER_AES256_OFB:
            keyLen = 32;
            ivLen = 16;
            isBlockMode = false;
            break;

        /* AEAD（GCM/ChaCha20-Poly1305）：常规 12B IV；纯吞吐无需显式设置 tag */
        case CRYPT_CIPHER_AES128_GCM:
            keyLen = 16;
            ivLen = 12;
            isBlockMode = false;
            break;
        case CRYPT_CIPHER_AES192_GCM:
            keyLen = 24;
            ivLen = 12;
            isBlockMode = false;
            break;
        case CRYPT_CIPHER_AES256_GCM:
            keyLen = 32;
            ivLen = 12;
            isBlockMode = false;
            break;
        case CRYPT_CIPHER_CHACHA20_POLY1305:
            keyLen = 32;
            ivLen = 12;
            isBlockMode = false;
            break;

        /* SM4 */
        case CRYPT_CIPHER_SM4_CBC:
            keyLen = 16;
            ivLen = 16;
            needNoPadding = true;
            break;
        case CRYPT_CIPHER_SM4_CTR:
            keyLen = 16;
            ivLen = 16;
            isBlockMode = false;
            break;
        case CRYPT_CIPHER_SM4_CFB:
            keyLen = 16;
            ivLen = 16;
            isBlockMode = false;
            break;
        case CRYPT_CIPHER_SM4_OFB:
            keyLen = 16;
            ivLen = 16;
            isBlockMode = false;
            break;
        case CRYPT_CIPHER_SM4_GCM:
            keyLen = 16;
            ivLen = 12;
            isBlockMode = false;
            break;

        /* XTS：双 key，给 256-bit 口径；Final 仍需调用 */
        case CRYPT_CIPHER_SM4_XTS:
            keyLen = 32;
            ivLen = 16;
            isBlockMode = true;
            needNoPadding = true;
            break;

        default:
/* 兜底：如果库提供 GetInfo，可查询推荐 key/iv 长度 */
#ifdef CRYPT_EAL_CipherGetInfo
        {
            uint32_t v;
            if (CRYPT_EAL_CipherGetInfo((CRYPT_CIPHER_AlgId)ciphId, /*KEY_LEN*/ 0, &v) == CRYPT_SUCCESS) {
                keyLen = v;
            }
            if (CRYPT_EAL_CipherGetInfo((CRYPT_CIPHER_AlgId)ciphId, /*IV_LEN*/ 1, &v) == CRYPT_SUCCESS) {
                ivLen = v;
            }
        }
#endif
        break;
    }
    uint8_t *key = (uint8_t *)malloc(keyLen ? keyLen : 1);
    uint8_t *iv = (uint8_t *)malloc(ivLen ? ivLen : 1);
    uint8_t *base_in = (uint8_t *)malloc(sz + misalign);
    uint8_t *base_out = (uint8_t *)malloc(sz + 32 + misalign);
    if (!key || !iv || !base_in || !base_out) {
        ret = HITLS_APP_MEM_ALLOC_FAIL;
        goto EXIT;
    }
    uint8_t *in = base_in + misalign; // 错位后的输入缓冲区
    uint8_t *out = base_out + misalign; // 错位后的输出缓冲区
    memset(key, 0x11, keyLen);
    memset(iv, 0x22, ivLen);
    memset(base_in, 0xA5, sz + misalign);

    if (isBlockMode && needNoPadding) {
        (void)CRYPT_EAL_CipherSetPadding(ctx, CRYPT_PADDING_NONE);
    }

    if (CRYPT_EAL_CipherInit(ctx, key, keyLen, ivLen ? iv : NULL, ivLen, !decrypt) != CRYPT_SUCCESS) {
        ret = HITLS_APP_CRYPTO_FAIL;
        goto EXIT;
    }

    uint64_t start = NsNow();
    uint64_t processed = 0;
    do {
        uint32_t outLen = sz + 32;
        if (CRYPT_EAL_CipherUpdate(ctx, in, sz, out, &outLen) != CRYPT_SUCCESS) {
            ret = HITLS_APP_CRYPTO_FAIL;
            goto EXIT;
        }
        processed += sz;
    } while (((double)(NsNow() - start) / 1e9) < (double)seconds);

    {
        uint32_t last = 0;
        (void)CRYPT_EAL_CipherFinal(ctx, out, &last);
    }

    double secs = (double)(NsNow() - start) / 1e9;
    if (secs <= BENCH_SECS_EPS) {
        secs = BENCH_SECS_EPS;
    }
    *bytesPerSecOut = (double)processed / secs;

EXIT:
    if (ctx) {
        CRYPT_EAL_CipherFreeCtx(ctx);
    }
    free(key);
    free(iv);
    free(base_in); // 释放基地址
    free(base_out); // 释放基地址
    return ret;
}

/* AEAD 基准：使用 CipherCtrl 设置/获取 AAD 与 TAG，带 debug 打印 */
static int32_t RunAeadOnce(uint32_t ciphId, bool decrypt, uint32_t sz, uint32_t seconds, double *bytesPerSecOut)
{
    int32_t ret = HITLS_APP_SUCCESS;
    CRYPT_EAL_CipherCtx *ctx = NULL; // 初始化为 NULL

    (void)decrypt;
    if (bytesPerSecOut) {
        *bytesPerSecOut = 0.0;
    }

    /* 分配缓冲区 */
    uint32_t keyLen = 16, ivLen = 12, aadLen = 16, tagLen = 16;
    uint8_t *key = malloc(keyLen);
    uint8_t *iv = malloc(ivLen);
    uint8_t *pt = malloc(sz);
    uint8_t *ct = malloc(sz + 64);
    uint8_t *aad = malloc(aadLen);
    uint8_t tag[16];
    uint32_t outLen = sz + 64, last = 0;

    if (!key || !iv || !pt || !ct || !aad) {
        ret = HITLS_APP_MEM_ALLOC_FAIL;
        goto EXIT;
    }

    memset(key, 0x11, keyLen);
    memset(iv, 0x22, ivLen);
    memset(pt, 0xA5, sz);
    memset(aad, 0x33, aadLen);

    ctx = CRYPT_EAL_CipherNewCtx((CRYPT_CIPHER_AlgId)ciphId);
    if (!ctx) {
        ret = HITLS_APP_MEM_ALLOC_FAIL;
        goto EXIT;
    }

    printf("[DEBUG] RunAeadOnce start: ciphId=%u, sz=%u\n", ciphId, sz);
    fflush(stdout);

    /* 循环计时执行 AEAD 加密 */
    uint64_t start = NsNow();
    uint64_t processed = 0;
    while (((double)(NsNow() - start) / 1e9) < (double)seconds) {
        outLen = sz + 64;
        ret = CRYPT_EAL_CipherInit(ctx, key, keyLen, iv, ivLen, true);
        ret = CRYPT_EAL_CipherCtrl(ctx, CRYPT_CTRL_SET_TAGLEN, &tagLen, sizeof(tagLen));
        ret = CRYPT_EAL_CipherCtrl(ctx, CRYPT_CTRL_SET_AAD, aad, aadLen);
        ret = CRYPT_EAL_CipherUpdate(ctx, pt, sz, ct, &outLen);
        last = 0;
        ret = CRYPT_EAL_CipherFinal(ctx, ct + outLen, &last);
        ret = CRYPT_EAL_CipherCtrl(ctx, CRYPT_CTRL_GET_TAG, tag, tagLen);

        processed += sz;
    }

    if (bytesPerSecOut) {
        double elapsedSecs = (double)(NsNow() - start) / 1e9;
        if (elapsedSecs < 1e-9) {
            elapsedSecs = 1e-9;
        }
        *bytesPerSecOut = (double)processed / elapsedSecs;
    }

EXIT:
    if (ctx) {
        CRYPT_EAL_CipherFreeCtx(ctx);
    }
    free(key);
    free(iv);
    free(pt);
    free(ct);
    free(aad);

    return ret;
}

static void PrintHuman(BenchOptCtx *opt, const char *kind, const char *algName, uint32_t sz, double bps)
{
    double mbps = bps / (1024.0 * 1024.0);
    BSL_PRINT_Fmt(0, opt->outUio, "%s %s %u bytes: %0.2f MB/s\n", kind, algName, sz, mbps);
}

static void PrintMr(BenchOptCtx *opt, const char *kind, const char *algName, uint32_t sz, double bps)
{
    /* 参照 openssl speed -mr：一行一条、易于脚本解析 */
    BSL_PRINT_Fmt(0, opt->outUio, "+F:%s:%s:%u:%.6f:%u\n", kind, algName, sz, bps, opt->seconds);
}

/* --------- 测试内核：素数生成 --------- */
static int32_t RunPrimeGenOnce(uint32_t bits, uint32_t seconds, double *primesPerSecOut)
{
    uint64_t start = NsNow();
    uint64_t endNs = start + (uint64_t)seconds * 1000000000ull;
    uint32_t primeCount = 0;
    int32_t ret = HITLS_APP_SUCCESS;

    /* 初始化随机数生成器 */
    if (CRYPT_EAL_RandInit(CRYPT_RAND_SHA256, NULL, NULL, NULL, 0) != CRYPT_SUCCESS) {
        AppPrintError("bench: Failed to initialize random number generator.\n");
        return HITLS_APP_CRYPTO_FAIL;
    }

    /* 创建优化器 */
    BN_Optimizer *opt = BN_OptimizerCreate();
    if (opt == NULL) {
        AppPrintError("bench: Failed to create BN optimizer.\n");
        CRYPT_EAL_RandDeinit();
        return HITLS_APP_MEM_ALLOC_FAIL;
    }

    /* 启动优化器 */
    if (OptimizerStart(opt) != CRYPT_SUCCESS) {
        AppPrintError("bench: Failed to start BN optimizer.\n");
        BN_OptimizerDestroy(opt);
        CRYPT_EAL_RandDeinit();
        return HITLS_APP_CRYPTO_FAIL;
    }

    while (NsNow() < endNs) {
        BN_BigNum *prime = BN_Create(bits);
        if (prime == NULL) {
            AppPrintError("bench: Failed to create BigNum for %u bit prime.\n", bits);
            ret = HITLS_APP_MEM_ALLOC_FAIL;
            break;
        }

        /* 生成指定位数的素数 */
        int32_t genResult = BN_GenPrime(prime, NULL, bits, false, opt, NULL);
        if (genResult != CRYPT_SUCCESS) {
            AppPrintError("bench: BN_GenPrime failed for %u bits, error code: %d.\n", bits, genResult);
            BN_Destroy(prime);
            ret = HITLS_APP_CRYPTO_FAIL;
            break;
        }

        BN_Destroy(prime);
        primeCount++;
    }

    /* 清理优化器 */
    OptimizerEnd(opt);
    BN_OptimizerDestroy(opt);

    /* 清理随机数生成器 */
    CRYPT_EAL_RandDeinit();

    if (ret != HITLS_APP_SUCCESS) {
        return ret;
    }

    if (primeCount == 0) {
        AppPrintError("bench: No primes were generated in the given time.\n");
        return HITLS_APP_CRYPTO_FAIL;
    }

    uint64_t actualTime = NsNow() - start;
    double secs = (double)actualTime / 1e9;
    if (secs <= BENCH_SECS_EPS) {
        secs = BENCH_SECS_EPS;
    }
    *primesPerSecOut = (double)primeCount / secs;

    return HITLS_APP_SUCCESS;
}
/* --------- 输出 --------- */
static void PrintResult(BenchOptCtx *opt, const char *algType, const char *algName, uint32_t size, const char *sizeUnit,
                        double value, const char *valueUnit)
{
    if (opt->mr) {
        /* 机器可读格式：+F:type:alg:size:value:duration */
        BSL_PRINT_Fmt(0, opt->outUio, "+F:%s:%s:%u:%.6f:%u\n", algType, algName, size, value, opt->seconds);
    } else if (opt->verbose) {
        /* 详细格式 */
        BSL_PRINT_Fmt(0, opt->outUio, "%-8s %-15s %6u %-5s: %12.6f %s (avg over %us)\n", algType, algName, size,
                      sizeUnit, value, valueUnit, opt->seconds);
    } else {
        /* 标准格式 */
        if (strcmp(valueUnit, "MB/s") == 0) {
            BSL_PRINT_Fmt(0, opt->outUio, "%-8s %-15s %6u %-5s: %8.2f %s\n", algType, algName, size, sizeUnit, value,
                          valueUnit);
        } else {
            BSL_PRINT_Fmt(0, opt->outUio, "%-8s %-15s %6u %-5s: %8.3f %s\n", algType, algName, size, sizeUnit, value,
                          valueUnit);
        }
    }
}

static void PrintTestHeader(BenchOptCtx *opt, const char *testType)
{
    if (opt->mr) {
        return;
    }

    if (opt->verbose) {
        BSL_PRINT_Fmt(0, opt->outUio, "=== %s Performance Test ===\n", testType);
        BSL_PRINT_Fmt(0, opt->outUio, "Test duration: %u seconds per size\n", opt->seconds);
        BSL_PRINT_Fmt(0, opt->outUio, "Timing method: %s\n", opt->elapsed ? "elapsed (wall-clock)" : "process time");
        BSL_PRINT_Fmt(0, opt->outUio, "\n");
        BSL_PRINT_Fmt(0, opt->outUio, "%-8s %-15s %6s %-5s  %12s %-10s\n", "Type", "Algorithm", "Size", "Unit",
                      "Performance", "Unit");
        BSL_PRINT_Fmt(0, opt->outUio, "------------------------------------------------------------------------\n");
    } else {
        BSL_PRINT_Fmt(0, opt->outUio, "%s Performance:\n", testType);
        BSL_PRINT_Fmt(0, opt->outUio, "%-8s %-15s %6s %-5s  %8s %-10s\n", "Type", "Algorithm", "Size", "Unit", "Perf",
                      "Unit");
        BSL_PRINT_Fmt(0, opt->outUio, "--------------------------------------------------------\n");
    }
}
typedef struct {
    BenchOptCtx *opt;
    uint32_t size;
    double resultBps;
    int32_t ret;
} AsyncJobCtx;

static void *AsyncJobRunner(void *arg) {
    AsyncJobCtx *ctx = (AsyncJobCtx *)arg;
    ctx->resultBps = 0.0;
    ctx->ret = HITLS_APP_OPT_VALUE_INVALID;

    switch (ctx->opt->kind) {
        case BENCH_ALG_MD:
            ctx->ret = RunMdOnce(ctx->opt->mdId, ctx->size, ctx->opt->seconds, &ctx->resultBps, ctx->opt->misalign);
            break;
        case BENCH_ALG_CIPHER:
            if (ctx->opt->aead) {
                ctx->ret = RunAeadOnce(ctx->opt->ciphId, ctx->opt->decrypt, ctx->size, ctx->opt->seconds, &ctx->resultBps);
            } else {
                ctx->ret = RunCipherOnce(ctx->opt->ciphId, ctx->opt->decrypt, ctx->size, ctx->opt->seconds, &ctx->resultBps, ctx->opt->misalign);
            }
            break;
        case BENCH_ALG_HMAC:
            ctx->ret = RunHmacOnce(ctx->opt->evpName, ctx->size, ctx->opt->seconds, &ctx->resultBps);
            break;
        case BENCH_ALG_CMAC:
            ctx->ret = RunCmacOnce(ctx->opt->evpName, ctx->size, ctx->opt->seconds, &ctx->resultBps);
            break;
        default:
            ctx->ret = HITLS_APP_OPT_VALUE_INVALID;
            break;
    }
    return NULL;
}
/* --------- 主执行 --------- */
static int32_t DoBench(BenchOptCtx *opt)
{
    int32_t ret = HITLS_APP_SUCCESS;
    opt->outUio = HITLS_APP_UioOpen(NULL, 'w', 0);
    if (opt->outUio == NULL) {
        return HITLS_APP_UIO_FAIL;
    }
    BSL_UIO_SetIsUnderlyingClosedByUio(opt->outUio, true);
    if (opt->mlock && enable_mlock() != 0) {
        BSL_UIO_Free(opt->outUio); // 释放已分配的 UIO
        opt->outUio = NULL;
        return HITLS_APP_INTERNAL_EXCEPTION; // 权限不足或系统调用失败
    }
    PrintSystemInfo(opt);
    

    ret = InitCryptoProvider(opt);
    if (ret != HITLS_APP_SUCCESS) {
        return ret;
    }

    const char *algName;
    if (opt->evpName[0] != '\0') {
        algName = opt->evpName;
    } else if (opt->kind == BENCH_ALG_MD || opt->kind == BENCH_ALG_CIPHER) {
        algName = HITLS_APP_GetNameByCid(
            (opt->kind == BENCH_ALG_MD ? opt->mdId : opt->ciphId),
            (opt->kind == BENCH_ALG_MD ? HITLS_APP_LIST_OPT_DGST_ALG : HITLS_APP_LIST_OPT_CIPHER_ALG));
    } else {
        algName = "unknown";
    }

    /* === 新增：AEAD 尺寸集切换（仅当未用 -bytes 且确实是 AEAD 算法） === */
    if (opt->kind == BENCH_ALG_CIPHER && opt->aead && !opt->useBytesOnly) {
        if (!IsAeadCipher(opt->ciphId)) {
            AppPrintError(
                "bench: -aead can only be used with AEAD algorithms (e.g., aes-*-gcm, chacha20-poly1305, sm4-gcm).\n");
            BSL_UIO_Free(opt->outUio);
            opt->outUio = NULL;
            return HITLS_APP_OPT_VALUE_INVALID;
        }
        static const uint32_t aeadSizes[] = {2, 31, 136, 1024, 8192, 16384};
        memcpy(opt->sizes, aeadSizes, sizeof(aeadSizes));
        opt->sizesCnt = (uint32_t)(sizeof(aeadSizes) / sizeof(aeadSizes[0]));
    }

    if (opt->kind == BENCH_ALG_PRIME) {
        const char *testName = "Prime Number Generation (specified by -primes)";
        const char *algType = "prime";
        const char *opName = "generate";

        PrintTestHeader(opt, testName);

        for (uint32_t i = 0; i < opt->primeSizesCnt; ++i) {
            uint32_t bits = opt->primeSizes[i];
            PrintProgress(opt, "Generating primes", i, opt->primeSizesCnt);
            double primesPerSec = 0.0;

            /* 调用素数生成测试 */
            ret = RunPrimeGenOnce(bits, opt->seconds, &primesPerSec);
            if (ret != HITLS_APP_SUCCESS) {
                AppPrintError("bench: Prime generation failed for %u bits.\n", bits);
                BSL_UIO_Free(opt->outUio);
                opt->outUio = NULL;
                return ret;
            }

            PrintProgressDone(opt);
            PrintResult(opt, algType, opName, bits, "bits", primesPerSec, "primes/s");
        }

    } else if (opt->kind == BENCH_ALG_RSA) {
        // /*TODO:evp rsa测试*/
    } else {
        const char *testType = (opt->kind == BENCH_ALG_MD) ? "Message Digest" : "Symmetric Cipher";
        PrintTestHeader(opt, testType);
        for (uint32_t i = 0; i < opt->sizesCnt; ++i) {
            uint32_t sz = opt->sizes[i];
            /* 异步线程模式 */
            if (opt->asyncJobs > 1) {
                // 线程逻辑
                uint32_t njobs = opt->asyncJobs;
    pthread_t *threads = (pthread_t *)calloc(njobs, sizeof(pthread_t));
    AsyncJobCtx *jobs = (AsyncJobCtx *)calloc(njobs, sizeof(AsyncJobCtx));
    if (!threads || !jobs) {
        free(threads); free(jobs);
        BSL_UIO_Free(opt->outUio); opt->outUio = NULL;
        return HITLS_APP_MEM_ALLOC_FAIL;
    }

    for (uint32_t j = 0; j < njobs; ++j) {
        jobs[j].opt = opt;
        jobs[j].size = sz;
        jobs[j].resultBps = 0.0;
        jobs[j].ret = HITLS_APP_OPT_VALUE_INVALID;
        if (pthread_create(&threads[j], NULL, AsyncJobRunner, &jobs[j]) != 0) {
            ret = HITLS_APP_UIO_FAIL;
            njobs = j;
            goto ASYNC_CLEANUP;
        }
    }

    double sumBps = 0.0;
    for (uint32_t j = 0; j < njobs; ++j) {
        pthread_join(threads[j], NULL);
        if (jobs[j].ret != HITLS_APP_SUCCESS) ret = jobs[j].ret;
        sumBps += jobs[j].resultBps;
    }

    if (ret == HITLS_APP_SUCCESS) {
        if (opt->mr) {
            PrintMr(opt, (opt->kind == BENCH_ALG_MD ? "md" : (opt->decrypt ? "dec" : "enc")), algName, sz, sumBps);
        } else {
            PrintHuman(opt, (opt->kind == BENCH_ALG_MD ? "md" : (opt->decrypt ? "dec" : "enc")), algName, sz, sumBps);
        }
    }

ASYNC_CLEANUP:
    free(threads);
    free(jobs);
    if (ret != HITLS_APP_SUCCESS) {
        BSL_UIO_Free(opt->outUio);
        opt->outUio = NULL;
        return ret;
            }
            continue; // 完成异步后直接跳过单进程处理
            }


            /* 单进程（默认）路径 */
            /* 单进程（默认）路径 */
            if (opt->multi <= 1) {
                double bps = 0.0;
                if (opt->kind == BENCH_ALG_MD) {
                    ret = RunMdOnce(opt->mdId, sz, opt->seconds, &bps, opt->misalign);
                } else if (opt->kind == BENCH_ALG_CIPHER) {
                    /* === 仅此处新增：支持 AEAD 的单次运行 === */
                    if (opt->aead) {
                        ret = RunAeadOnce(opt->ciphId, opt->decrypt, sz, opt->seconds, &bps);
                    } else {
                        ret = RunCipherOnce(opt->ciphId, opt->decrypt, sz, opt->seconds, &bps, opt->misalign);
                    }
                    /* === 新增结束 === */
                } else if (opt->kind == BENCH_ALG_HMAC) {
                    ret = RunHmacOnce(opt->evpName, sz, opt->seconds, &bps);
                } else if (opt->kind == BENCH_ALG_CMAC) {
                    ret = RunCmacOnce(opt->evpName, sz, opt->seconds, &bps);
                } else {
                    ret = HITLS_APP_OPT_VALUE_INVALID;
                }

                if (ret != HITLS_APP_SUCCESS) {
                    BSL_UIO_Free(opt->outUio);
                    opt->outUio = NULL;
                    return ret;
                }
                if (opt->mr) {
                    PrintMr(opt,
                            (opt->kind == BENCH_ALG_MD     ? "md" :
                             (opt->kind == BENCH_ALG_HMAC) ? "hmac" :
                             (opt->kind == BENCH_ALG_CMAC) ? "cmac" :
                                                             (opt->decrypt ? "dec" : "enc")),
                            algName, sz, bps);
                } else {
                    PrintHuman(opt,
                               (opt->kind == BENCH_ALG_MD     ? "md" :
                                (opt->kind == BENCH_ALG_HMAC) ? "hmac" :
                                (opt->kind == BENCH_ALG_CMAC) ? "cmac" :
                                                                (opt->decrypt ? "dec" : "enc")),
                               algName, sz, bps);
                }
                continue;
            }

            /* 单进程（默认）路径 */
            if (opt->multi <= 1) {
                double bps = 0.0;
                if (opt->kind == BENCH_ALG_MD) {
                    ret = RunMdOnce(opt->mdId, sz, opt->seconds, &bps, opt->misalign);
                } else if (opt->kind == BENCH_ALG_CIPHER) {
                    /* === 仅此处新增：支持 AEAD 的单次运行 === */
                    if (opt->aead) {
                        ret = RunAeadOnce(opt->ciphId, opt->decrypt, sz, opt->seconds, &bps);
                    } else {
                        ret = RunCipherOnce(opt->ciphId, opt->decrypt, sz, opt->seconds, &bps, opt->misalign);
                    }
                    /* === 新增结束 === */
                } else {
                    ret = HITLS_APP_OPT_VALUE_INVALID;
                }

                if (ret != HITLS_APP_SUCCESS) {
                    BSL_UIO_Free(opt->outUio);
                    opt->outUio = NULL;
                    return ret;
                }
                if (opt->mr) {
                    PrintMr(opt, (opt->kind == BENCH_ALG_MD ? "md" : (opt->decrypt ? "dec" : "enc")), algName, sz, bps);
                } else {
                    PrintHuman(opt, (opt->kind == BENCH_ALG_MD ? "md" : (opt->decrypt ? "dec" : "enc")), algName, sz,
                               bps);
                }
                continue;
            }

            /* multi > 1：并行多进程执行并聚合 */
            uint32_t n = opt->multi;
            pid_t *pids = (pid_t *)calloc(n, sizeof(pid_t));
            int (*pipes)[2] = (int (*)[2])calloc(n, sizeof(int[2]));
            if (pids == NULL || pipes == NULL) {
                free(pids);
                free(pipes);
                BSL_UIO_Free(opt->outUio);
                opt->outUio = NULL;
                return HITLS_APP_MEM_ALLOC_FAIL;
            }

            for (uint32_t t = 0; t < n; ++t) {
                if (pipe(pipes[t]) < 0) {
                    ret = HITLS_APP_UIO_FAIL;
                    n = t;
                    goto MULTI_CLEANUP_WAIT;
                }
                pid_t pid = fork();
                if (pid < 0) {
                    ret = HITLS_APP_UIO_FAIL;
                    n = t;
                    goto MULTI_CLEANUP_WAIT;
                }

                if (pid == 0) { /* 子进程 */
                    /* 子进程关闭读端，只写结果（double bps）回父进程 */
                    (void)close(pipes[t][0]);

                    double bps = 0.0;
                    int32_t cRet = HITLS_APP_SUCCESS;
                    if (opt->kind == BENCH_ALG_MD) {
                        cRet = RunMdOnce(opt->mdId, sz, opt->seconds, &bps, opt->misalign);
                    } else {
                        cRet = RunCipherOnce(opt->ciphId, opt->decrypt, sz, opt->seconds, &bps, opt->misalign);
                    }
                    if (cRet != HITLS_APP_SUCCESS) {
                        bps = -1.0; /* 失败标记 */
                    }

                    /* 保证写满，处理 EINTR/短写；父进程若读不满会视为失败 */
                    size_t to_write = sizeof(bps);
                    const unsigned char *wp = (const unsigned char *)&bps;
                    while (to_write > 0) {
                        ssize_t w = write(pipes[t][1], wp, to_write);
                        if (w < 0) {
                            if (errno == EINTR) {
                                continue; /* 被信号中断，重试 */
                            }
                            break; /* 其他写失败，父进程将据短读判失败 */
                        }
                        to_write -= (size_t)w;
                        wp += (size_t)w;
                    }

                    (void)close(pipes[t][1]);
                    _exit(0);
                } else { /* 父进程 */
                    pids[t] = pid;
                    (void)close(pipes[t][1]); /* 父进程只读 */
                }
            }

            /* 汇总各子进程吞吐 */
            {
                double sumBps = 0.0;
                for (uint32_t t = 0; t < n; ++t) {
                    double bps = 0.0;
                    size_t need = sizeof(bps);
                    uint8_t *p = (uint8_t *)&bps;
                    while (need > 0) {
                        ssize_t r = read(pipes[t][0], p, need);
                        if (r < 0) {
                            if (errno == EINTR) {
                                continue;
                            }
                            break;
                        }
                        if (r == 0) {
                            break; /* 对端关闭 */
                        }
                        need -= (size_t)r;
                        p += (size_t)r;
                    }
                    (void)close(pipes[t][0]);
                    if (need != 0 || !(bps >= 0.0)) { /* 读失败或子进程报错（负数标记） */
                        ret = HITLS_APP_CRYPTO_FAIL;
                    } else {
                        sumBps += bps;
                    }
                }

                /* 等待所有子进程退出 */
                for (uint32_t t = 0; t < n; ++t) {
                    if (pids[t] > 0) {
                        (void)waitpid(pids[t], NULL, 0);
                    }
                }

                free(pids);
                free(pipes);

                if (ret != HITLS_APP_SUCCESS) {
                    BSL_UIO_Free(opt->outUio);
                    opt->outUio = NULL;
                    return ret;
                }

                if (opt->mr) {
                    PrintMr(opt, (opt->kind == BENCH_ALG_MD ? "md" : (opt->decrypt ? "dec" : "enc")), algName, sz,
                            sumBps);
                } else {
                    PrintHuman(opt, (opt->kind == BENCH_ALG_MD ? "md" : (opt->decrypt ? "dec" : "enc")), algName, sz,
                               sumBps);
                }
            }
            continue;

MULTI_CLEANUP_WAIT:
            for (uint32_t t2 = 0; t2 < n; ++t2) {
                if (pipes) {
                    if (pipes[t2][0] >= 0) {
                        (void)close(pipes[t2][0]);
                    }
                    if (pipes[t2][1] >= 0) {
                        (void)close(pipes[t2][1]);
                    }
                }
                if (pids && pids[t2] > 0) {
                    (void)waitpid(pids[t2], NULL, 0);
                }
            }
            free(pids);
            free(pipes);
            BSL_UIO_Free(opt->outUio);
            opt->outUio = NULL;
            return ret;
        }
    }

    if (opt->verbose && !opt->mr) {
        BSL_PRINT_Fmt(0, opt->outUio, "\nBenchmark completed successfully.\n");
    }

    return ret;
}

/* --------- 入口 --------- */
int32_t HITLS_BENCHMain(int argc, char *argv[])
{
    BenchOptCtx opt;
    InitBenchOptCtx(&opt);

    int32_t ret = ParseBenchOpt(argc, argv, &opt);
    if (ret != HITLS_APP_SUCCESS) {
        return ret;
    }

    /* 如需与 OpenSSL 一样打印版本/CPU 信息，可在此补充（TODO） */

    ret = DoBench(&opt);

    BSL_UIO_Free(opt.outUio);
    opt.outUio = NULL;
    return ret;
}
